/**
 * Skitsanos as3Uploader, ported to be used with Vzaar API
 * @author Skitsanos
 * @version 1.5
 */
package
{
	import com.vzaar.uploader.S3UploadOptions;
	import com.vzaar.uploader.S3Uploader;

	import flash.events.DataEvent;
	import flash.events.Event;
	import flash.events.HTTPStatusEvent;
	import flash.events.IOErrorEvent;
	import flash.events.MouseEvent;
	import flash.events.ProgressEvent;
	import flash.events.SecurityErrorEvent;
	import flash.net.FileFilter;
	import flash.net.FileReference;
	import flash.net.FileReferenceList;
	import flash.net.URLLoader;
	import flash.net.URLRequest;
	import flash.net.URLRequestMethod;
	import flash.system.Security;
	import flash.ui.ContextMenu;
	import flash.ui.ContextMenuItem;

	import org.flashapi.swing.Alert;
	import org.flashapi.swing.Application;
	import org.flashapi.swing.Button;
	import org.flashapi.swing.DataGrid;
	import org.flashapi.swing.Label;
	import org.flashapi.swing.Panel;
	import org.flashapi.swing.PanelContainer;
	import org.flashapi.swing.Spacer;
	import org.flashapi.swing.TextInput;
	import org.flashapi.swing.constants.LayoutOrientation;
	import org.flashapi.swing.databinding.DataProvider;
	import org.flashapi.swing.databinding.XMLQuery;
	import org.flashapi.swing.event.ListEvent;
	import org.flashapi.swing.event.UIMouseEvent;
	import org.flashapi.swing.event.UIOEvent;

	public class VzaarUploader extends Application
	{
		private var uploadUrl:String = "";

		private var _refFiles:FileReferenceList;
		private var file:FileReference;
		private var fileQueue:Array = [];

		private var mimeTypes:Object = new Object();

		//shared UI controls
		private var txtUsername:TextInput;
		private var txtToken:TextInput;

		private var status:Label;
		private var btnUpload:Button;
		private var btnRemoveSelected:Button;
		private var btnClearAll:Button;

		private var grid:DataGrid;
		private var provider:DataProvider = new DataProvider();

		private var ctxmenu:ContextMenu;

		public function VzaarUploader()
		{
			super();

			Security.allowDomain("*");
			//Security.allowDomain('vz1.s3.amazonaws.com');
			//Security.loadPolicyFile('https://vz1.s3.amazonaws.com/crossdomain.xml');

			//mimeTypes.description = "Images (*.jpg, *.jpeg, *.gif, *.png)";
			//mimeTypes.extensions = "*.jpg; *.jpeg; *.gif; *.png";
			//Supported formats: avi, flv, m4v, mp4, mov, 3gp, wmv, mp3

			mimeTypes.description = "All Files (*.*)";
			mimeTypes.extensions = "*.*";

			ctxmenu = new ContextMenu();
			ctxmenu.hideBuiltInItems();
			this.contextMenu = ctxmenu;

			var menuCopyright:ContextMenuItem = new ContextMenuItem('VzaarUploader © 2010 - 2012, skitsanos.com');
			ctxmenu.customItems.push(menuCopyright);

			gradientBackground = bodyVisibility = true;

			stage.showDefaultContextMenu = false;

			var panel:PanelContainer = new PanelContainer('vzaar Bulk Uploader (v.2.0)');
			panel.layout.orientation = LayoutOrientation.VERTICAL;
			panel.addEventListener(UIOEvent.DISPLAYED, function (e:UIOEvent):void
			{
				panel.percentWidth = 97;
				panel.percentHeight = 94;
				panel.redraw();
			});
			this.addElement(panel);
			panel.display();

			//Authentication controls
			var barAuth:Panel = new Panel();
			barAuth.percentWidth = 100;
			barAuth.layout.orientation = LayoutOrientation.HORIZONTAL; // new GridLayout(2, 2, 5, 5);
			barAuth.height = 40;
			barAuth.color = 0xcdc9c9;
			barAuth.shadow = true;
			barAuth.fixToParentWidth = true;
			panel.addElement(barAuth);

			//add vzaar username field
			barAuth.addElement(new Label("vzaar username:"));
			txtUsername = new TextInput();
			txtUsername.width = 170;
			barAuth.addElement(txtUsername);

			//add vzaar api token field
			barAuth.addElement(new Label("vzaar token:"));
			txtToken = new TextInput();
			txtToken.percentWidth = 60;
			barAuth.addElement(txtToken);

			//controls bar
			var barControls:Panel = new Panel();
			barControls.gradientMode = false;
			barControls.percentWidth = 100;
			barControls.layout.orientation = LayoutOrientation.HORIZONTAL;
			barControls.color = 0xfffafa;
			barControls.height = 45;
			barControls.fixToParentWidth = true;
			panel.addElement(barControls);

			var btnBrowse:Button = new Button('Browse...');
			btnBrowse.addEventListener(UIMouseEvent.CLICK, btnBrowse_click);
			barControls.addElement(btnBrowse);

			btnRemoveSelected = new Button("Remove Selected");
			btnRemoveSelected.enabled = false;
			btnRemoveSelected.addEventListener(UIMouseEvent.CLICK, btnRemoveSelected_click);
			barControls.addElement(btnRemoveSelected);

			btnClearAll = new Button('Clear All');
			btnClearAll.enabled = false;
			btnClearAll.addEventListener(UIMouseEvent.CLICK, btnClearAll_click);
			barControls.addElement(btnClearAll);

			var uiSpacer:Spacer = new Spacer();
			uiSpacer.autoWidth = true;
			barControls.addElement(uiSpacer);

			btnUpload = new Button("Upload");
			btnUpload.enabled = false;
			btnUpload.addEventListener(MouseEvent.CLICK, _button_Upload_click);
			barControls.addElement(btnUpload);

			grid = new DataGrid();
			grid.fixToParentWidth = true;
			grid.fixToParentHeight = true;
			panel.addElement(grid);

			var panelStatus:Panel = new Panel();
			panelStatus.percentWidth = 97;
			panelStatus.height = 30;

			status = new Label('Iddle');
			panelStatus.addElement(status);
			this.addElement(panelStatus);

			var request:XMLQuery = new XMLQuery();

			var data:XML =
					<uploader>
						<dataGridColumns>
							<item dataField="name" headerText="File name"/>
							<item dataField="size" headerText="Size" width="150"/>
							<item dataField="progress" headerText="Progress"  width="300"/>
						</dataGridColumns>
					</uploader>;
			request.add(data);

			grid.xmlQuery = request;

			grid.addEventListener(ListEvent.LIST_CHANGED, function (e:ListEvent):void
			{
				if (e.currentTarget.listItem != null)
				{
					btnRemoveSelected.enabled = true;
					btnUpload.enabled = true;
					btnClearAll.enabled = true;
				}
			});

			grid.dataProvider = provider;

			//fix sizing and controls positions
			stage.addEventListener(Event.RESIZE, function (e:Event):void
			{
				panel.percentWidth = 97;
				panel.percentHeight = 94;

				panelStatus.percentWidth = 97;
			});
		}

		private function btnBrowse_click(e:UIMouseEvent):void
		{
			var filter:FileFilter = new FileFilter(mimeTypes.description, mimeTypes.extensions);

			/*file = new FileReference();
			 file.addEventListener(Event.SELECT, onSelectFile);
			 file.browse([filter]);    */

			var files:FileReferenceList = new FileReferenceList();
			files.addEventListener(Event.SELECT, function (selectEvent:Event):void
			{
				for (var i:uint = 0; i < files.fileList.length; i++)
				{
					var ref:FileReference = FileReference(files.fileList[i]);
					fileQueue.push(ref);
					grid.addItem({ name:ref.name, size:ref.size, progress:'0%' });

					btnUpload.enabled = true;
					btnRemoveSelected.enabled = false;
					btnClearAll.enabled = true;

					status.text = fileQueue.length + ' file(s) in queue';
				}
			});
			files.browse(filters);
		}

		private function btnRemoveSelected_click(e:UIMouseEvent):void
		{
			grid.removeItem(grid.listItem);
			fileQueue.splice(grid.listItem, 1);

			if (fileQueue.length < 1)
			{
				btnRemoveSelected.enabled = false;
				btnClearAll.enabled = false;
				btnUpload.enabled = false;
			}

			status.text = fileQueue.length + ' files in queue';
		}

		private function btnClearAll_click(e:UIMouseEvent):void
		{
			grid.removeAll();

			fileQueue = [];
			btnRemoveSelected.enabled = false;
			btnClearAll.enabled = false;
			btnUpload.enabled = false;
		}

		/**
		 * Upload selected files
		 *
		 * @param e
		 */
		private function _button_Upload_click(e:MouseEvent):void
		{
			if (txtUsername.text == '' || txtToken.text == '')
			{
				var alert:Alert = new Alert("Credentials missing");
				alert.message = "both vzaar username and token required to upload your videos!";
				alert.display();
			}
			else
			{
				if (fileQueue.length > 0)
				{
					VzaarCredentials.secret = txtUsername.text;
					VzaarCredentials.token = txtToken.text;

					status.text = "Uploading, please wait...";

					for each (var f:FileReference in fileQueue)
					{
						uploadVideo(f);
					}
				}
			}
		}

		private function _file_UploadComplete(e:DataEvent):void
		{
			var ref:FileReference = FileReference(e.currentTarget.fileReference);
			ref.removeEventListener(ProgressEvent.PROGRESS, _file_UploadProgress);
			ref.removeEventListener(Event.COMPLETE, _file_UploadComplete);

			for (var j:Number = 0; j < fileQueue.length; j++)
			{
				if (FileReference(fileQueue[j]).name == ref.name)
				{
					fileQueue.splice(j, 1);
					//grid.removeItemAt(j);

					var arrayOfKeys:Array = XML(e.data)..Key[0].toString().split('/');
					var guid:String = arrayOfKeys[arrayOfKeys.length - 2];

					var o:Object = grid.getItemAt(j).value;
					o.progress = 'Processing ' + guid + '...';
					grid.updateItemAt(j, o);

					//call Process Video for this GUID
					processVideo(j, guid);
				}
			}

			if (fileQueue.length < 1)
			{
				//grid.removeAll();
				btnClearAll.enabled = false;
				btnUpload.enabled = false;
				btnRemoveSelected.enabled = false;
			}

			status.text = fileQueue.length + ' files in queue';
		}

		private function _file_UploadIoError(e:IOErrorEvent):void
		{
			status.text = e.text;
		}

		/**
		 * handle permission denied errors
		 */
		private function _file_UploadHttpStatus(e:HTTPStatusEvent):void
		{
			if (e.status == 403)
			{
				var ref:FileReference = FileReference(e.currentTarget.fileReference);
				for (var j:Number = 0; j < fileQueue.length; j++)
				{
					if (FileReference(fileQueue[j]).name == ref.name)
					{
						var o:Object = grid.getItemAt(j).value;
						o.progress = 'ERROR (403)';

						grid.updateItemAt(j, o);
					}
				}
			}
		}

		private function _file_UploadProgress(e:ProgressEvent):void
		{
			var numPerc:Number = Math.round((e.bytesLoaded / e.bytesTotal) * 100);
			var ref:FileReference = FileReference(e.currentTarget.fileReference);
			for (var j:Number = 0; j < fileQueue.length; j++)
			{
				if (FileReference(fileQueue[j]).name == ref.name)
				{
					var o:Object = grid.getItemAt(j).value;
					trace(o.name + numPerc + '%');
					o.progress = numPerc + '%';

					grid.updateItemAt(j, o);
					//grid.getModel().setValueAt(numPerc + '%', j, 2);
				}
			}

			trace("uploaded " + numPerc + "%");
		}

		/**
		 * Upload video from local drive directly to Amazon S3 bucket
		 * @param string $path
		 * @return string GUID of the file uploaded
		 */
		public function uploadVideo(file:FileReference):void
		{
			var url:String = "http://api.skitsanos.com/vzaar/signature.php?token=" + VzaarCredentials.token + "&secret=" + VzaarCredentials.secret;
			var service:URLLoader = new URLLoader();
			service.addEventListener(Event.COMPLETE, function (e:Event):void
			{
				var loader:URLLoader = URLLoader(e.target);

				var result:Object = JSON.parse(loader.data.toString());

				var uploadOptions:S3UploadOptions = new S3UploadOptions();
				var guid:String = result.guid;
				uploadOptions.acl = result.acl;
				uploadOptions.policy = result.policy;
				uploadOptions.signature = result.signature;
				uploadOptions.contentType = 'binary/octet-stream';

				uploadOptions.secure = result.https;

				var s3Uploader:S3Uploader = new S3Uploader(result.accesskeyid,
						result.key,
						result.bucket,
						result.expirationdate,
						uploadOptions);

				s3Uploader.addEventListener(ProgressEvent.PROGRESS, _file_UploadProgress);
				s3Uploader.addEventListener(IOErrorEvent.IO_ERROR, _file_UploadIoError);
				s3Uploader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, function (e:SecurityErrorEvent):void
				{
					trace('Security Error');
				});
				s3Uploader.addEventListener(DataEvent.UPLOAD_COMPLETE_DATA, _file_UploadComplete);
				s3Uploader.addEventListener(HTTPStatusEvent.HTTP_STATUS, _file_UploadHttpStatus);

				s3Uploader.upload(file);
			});

			var urlReq:URLRequest = new URLRequest(url);
			urlReq.method = URLRequestMethod.GET;

			try
			{
				service.load(urlReq);
			} catch (error:Error)
			{
				trace("Unable to load requested document.");
			}
		}

		/**
		 * Process Video
		 * @param rowId Row ID in the list of videos
		 * @param guid GUID returned by vzaar API
		 */
		private function processVideo(rowId:int, guid:String):void
		{
			var url:String = "http://api.skitsanos.com/vzaar/process.php?token=" + VzaarCredentials.token + "&secret=" + VzaarCredentials.secret + '&guid=' + guid + '&title=' + grid.getItemAt(rowId).value.name;
			var service:URLLoader = new URLLoader();

			service.addEventListener(Event.COMPLETE, function (e:Event):void
			{
				var loader:URLLoader = URLLoader(e.target);
				var result:String = loader.data.toString();
				var o:Object = grid.getItemAt(rowId).value;
				o.progress = 'Video ID: ' + result;

				grid.updateItemAt(rowId, o);
			});

			var urlReq:URLRequest = new URLRequest(url);
			urlReq.method = URLRequestMethod.GET;

			try
			{
				service.load(urlReq);
			} catch (error:Error)
			{
				trace("Unable to load requested document.");
			}
		}
	}
}